package org.jkuang.qstar.index.parser;

import java.util.Stack;

import org.apache.log4j.Logger;
import org.jkuang.qstar.index.dic.TermsDic;

/**
 * 
 * @author jkuang 2012年11月17日
 *
 */
public class SyntaxParser {

	static final char LEFT_BRACKET = '(';
	static final char RIGHT_BRACKET = ')';

	static final char OP = 'O';
	static final char VALUE = 'V';

	static final char AND = '&';
	static final char OR = '|';
	static final char BLANK = ' ';

	static final String _AND = "AND";
	static final String _OR = "OR";

	TermsDic dic;
	private int bracket_mark = 0;
	private char lastValue = BLANK;
	Stack<ParserParam> stacks = new Stack<ParserParam>();
	Stack<Character> operators = new Stack<Character>();

	static Logger logger = Logger.getLogger("SyntaxParser");

	public SyntaxParser(TermsDic dic) {
		this.dic = dic;
	}

	public static void main(String[] args) {
		String syntax = "(windcode:T.IPE) OR (windcode:AG(T+D).SGE)";
		TermsDic dic = new TermsDic(true);
		dic.add("windcode:T.IPE");
		dic.add("windcode:AG(T+D).SGE");
		SyntaxParser parser = new SyntaxParser(dic);

		parser.parser(syntax);
	}

	/**
	 * 将语法中的参数值通过词典转换为整形对象
	 * 
	 * @param vl 参数值
	 * @return 词典对应的整形，若不存在，则返回Int.MIN
	 */
	private int getValue(String vl) {

		return dic.get(vl);
	}

	/**
	 * 解析语法，生成最简化参数
	 * 
	 * @param text 语法表达式，A AND B 格式
	 * @return
	 */
	public ParserParam parser(String text) {

		char[] ch = text.toCharArray();
		char[] value = new char[text.length() * 2];
		StringBuffer temp = new StringBuffer();
		int index = 0;
		for (int i = 0; i < ch.length; i++) {
			if (ch[i] == RIGHT_BRACKET) {
				if (--bracket_mark < 0) {
					logger.error("语法在第" + (i + 1) + "字符处发现括号不匹配:" + text);
					return new ParserParam(-1);
				}
				value[index++] = ch[i];
				value[index++] = ' ';
				// 执行出栈
				if (temp.length() > 0) {
					// 如果当前是数值，不允许上个值是右括号
					if (lastValue == RIGHT_BRACKET || lastValue == VALUE) {
						logger.error("语法发现错误，值 '" + temp + "' 前不允许是右括号或者值");
						return new ParserParam(-1);
					}
					lastValue = VALUE;
					this.addTerms(temp);
					temp.delete(0, temp.length());
					// 标记数据
				}
				this.processRightBracket(i == ch.length - 1);
				// 标记是括号
				if (lastValue == OP) {
					logger.error("语法在第" + (i + 1) + "字符处发现语法错误，有括号前出现操作符" + text);
					return new ParserParam(-1);
				} else {
					lastValue = RIGHT_BRACKET;
				}
			} else if (ch[i] == LEFT_BRACKET) {
				this.bracket_mark++;
				if (i > 0 && value[index - 1] != BLANK) {
					value[index++] = BLANK;
				}
				value[index++] = ch[i];
				if (this.lastValue == RIGHT_BRACKET || this.lastValue == VALUE) {
					logger.error("语法错误，在第" + (i + 1) + "个字符处发现左括号前为有括号或值：" + text);
					return new ParserParam(-1);
				}
				this.lastValue = LEFT_BRACKET;
				this.operators.push(LEFT_BRACKET);
			} else if (ch[i] == BLANK) {
				if (index > 0 && value[index - 1] != BLANK) {
					value[index++] = BLANK;
				}

				if (temp.length() > 0 && !(temp.toString().equals(_AND) || temp.toString().equals(_OR))) {

					// 如果当前是数值，不允许上个值是右括号
					if (this.lastValue == RIGHT_BRACKET || this.lastValue == VALUE) {

						logger.error("语法错误，在第" + (i + 1) + "个字符处发现值前缺少操作符：" + text);
						return new ParserParam(-1);
					}
					this.lastValue = VALUE;
					this.addTerms(temp);
				}
				temp.delete(0, temp.length());
			} else {
				value[index++] = ch[i];
				temp.append(value[index - 1]);
				if (i == ch.length - 1) {
					if (temp.length() > 0) {
						// 如果当前是数值，则语法的上个指不允许是值，只能是括号，操作符
						if (this.lastValue != BLANK && this.lastValue != OP) {
							logger.error("语法错误，在第" + (i + 1) + "个字符处发现值前缺少操作符：" + text);
							return new ParserParam(-1);
						}
						this.lastValue = VALUE;
						this.addTerms(temp);
						temp.delete(0, temp.length());
					}
				}
			}
			if (i == ch.length - 1) {
				if (bracket_mark != 0) {
					logger.error("语法错误，括号不匹配！" + text);
					return new ParserParam(-1);
				}
				// 结尾只允许是数值,右括号
				if (this.lastValue == OP || this.lastValue == LEFT_BRACKET) {
					logger.error("语法错误语法在结尾值允许为操作符或右括号：" + text);
					return new ParserParam(-1);
				}
				return this.finish();
			} else {
				char tempLast = this.lastValue;
				if (pushOperator(value, index, temp) && tempLast == OP) {
					logger.error("语法错误，操作符号之间没有值！：" + text);
					return new ParserParam(-1);
				}
			}
		}
		return this.finish();
	}

	/**
	 * 如果是操作符号，则操作符号入栈
	 * 
	 * @param value
	 * @param index
	 * @param temp
	 * @return
	 */
	private boolean pushOperator(char[] value, int index, StringBuffer temp) {
		if (index >= 4 && value[index - 1] == BLANK) {
			if (index > 4 && value[index - 2] == 'D' && value[index - 3] == 'N' && value[index - 4] == 'A'
					&& value[index - 5] == BLANK) {
				value[index - 5] = 2;
				index -= 4;
				this.lastValue = OP;
				this.operators.push(AND);
				temp.delete(0, temp.length());
				return true;
			} else if (value[index - 2] == 'R' && value[index - 3] == 'O' && value[index - 4] == BLANK) {
				value[index - 4] = 0;
				index -= 3;
				this.lastValue = OP;
				this.operators.push(OR);
				temp.delete(0, temp.length());
				return true;
			}
		}
		return false;
	}

	/**
	 * 添加值
	 * 
	 * @param buffer
	 * @param vls
	 */
	private void addTerms(StringBuffer buffer) {
		int vl = getValue(buffer.toString());
		if (operators.size() == 0) {
			stacks.push(new ParserParam(vl));
			return;
		} else {
			switch (operators.peek()) {
			case AND:
				operators.pop();
				stacks.peek().addAND(vl);
				break;
			case OR:
			case LEFT_BRACKET:
				stacks.push(new ParserParam(vl));
				break;
			default:
				break;
			}
		}

	}

	// 处理遇到右括号
	private void processRightBracket(boolean isEnd) {
		if (stacks.size() == 0) {
			System.out.println("parser error!");
			return;
		}
		ParserParam value = stacks.pop();
		int opType;
		while ((opType = operators.pop()) != LEFT_BRACKET) {
			if (stacks.size() == 0) {
				System.out.println("parser error!");
				return;
			}
			switch (opType) {
			case OR:
				value.OR(stacks.pop());
				break;
			default:
				System.err.println("括号处理错误");
				break;
			}
		}
		while (operators.size() > 0 && operators.peek() == AND) {
			operators.pop();
			if (stacks.size() == 0) {
				System.out.println("parser error!");
				return;
			}
			ParserParam param = stacks.pop();
			if (isEnd && stacks.size() == 0 && value.getResult().size()
					* param.getResult().size() > (value.getResult().size() + param.getResult().size())) {
				value.getFilter().addAll(param.getResult());
			} else {
				value.AND(param);
			}
		}
		stacks.push(value);
	}

	/**
	 * 结束语法解析
	 * 
	 * @return
	 */
	private ParserParam finish() {
		ParserParam value = stacks.pop();
		while (operators.size() > 0) {
			int opType = operators.pop();
			switch (opType) {
			case OR:
				value.OR(stacks.pop());
				break;
			case AND:
				value.AND(stacks.pop());
				System.out.println("语法and解析错误 ");
				break;
			case LEFT_BRACKET:
				System.out.println("语法括号错误");
				break;
			default:
				System.out.println("语法括号错误");
				break;
			}
		}
		return value;
	}
}
